/*
    Name    : Multi-scale Retinex Base-code
    Author  : Junyoung Park <junyoung.park@kaist.ac.kr>
    
    History :
        2011-10-14 first draft

*/

#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <iostream>
#include "asretinex.h"

int main( int argc, char** argv )
{
    using namespace cv;
    Mat image;

    const char *oriImageWindow = "Original Image";
    const char *outputImageWindow1 = "Output Image1";
    const char *outputImageWindow2 = "Output Image2";
    const char *outputImageWindow3 = "Output Image3";    

    image = imread( "test.png", 1 );

    std::cout << "image col     : " << image.cols << std::endl;
    std::cout << "image row     : " << image.rows << std::endl;
    std::cout << "image dep     : " << image.depth() << std::endl;
    std::cout << "image channels: " << image.channels() << std::endl;
    
    Mat image_r( image.rows, image.cols, CV_8UC1);
    Mat image_g( image.rows, image.cols, CV_8UC1);
    Mat image_b( image.rows, image.cols, CV_8UC1);
    
    Mat image_retinex;

    Mat out[] = { image_r, image_g, image_b };
    int from_to[] = { 0,0, 1,1, 2,2 };
    mixChannels( &image, 1, out, 3, from_to, 3 );

//    image_r = image_g.t();

    CScaleRetinex test;
    image_retinex = test.run_retinex( image_r );

/*
    CScaleRetinex test;
//    test.run_sr( 
//        void run_sr(double *src, int width, int height, double *dst);


    for (int i=0;i<image.rows;i++)
        for (int j=0;j<image.cols;j++)
        {
            image.at<Vec3b>(i,j) = Vec3b(255,255,255) - image.at<Vec3b>(i,j);
//           image.at<unsigned char>(i,j,1) = 255 - image.at<unsigned char>(i,j,1);
//           image.at<unsigned char>(i,j,2) = 255 - image.at<unsigned char>(i,j,2);
        }

*/
    namedWindow(oriImageWindow,CV_WINDOW_AUTOSIZE );
    namedWindow(outputImageWindow1,CV_WINDOW_AUTOSIZE );
    namedWindow(outputImageWindow2,CV_WINDOW_AUTOSIZE );
//    namedWindow(outputImageWindow3,CV_WINDOW_AUTOSIZE );

    imshow( oriImageWindow, image );
    imshow( outputImageWindow1, image_r );
//    imshow( outputImageWindow2, image_g );
    imshow( outputImageWindow2, image_retinex );
//    imshow( outputImageWindow3, image_b );

    waitKey(0);

    return 0;
}



/*

    [OpenCV Personal Note]

    [1] int Mat::depth() const

        Returns matrix element depth
        The method returns the matrix element depth id,
        i.e. the type of each individual channel.
        For example, for 16-bit signed 3-channel array the method will return CV_16S.
        The complete list of matrix types:

    CV_8U - 8-bit unsigned integers ( 0..255 )
    CV_8S - 8-bit signed integers ( -128..127 )
    CV_16U - 16-bit unsigned integers ( 0..65535 )
    CV_16S - 16-bit signed integers ( -32768..32767 )
    CV_32S - 32-bit signed integers ( -2147483648..2147483647 )
    CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN )
    CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )


    [2] using multi-channel color images -> use Vector array!

    e.g) simple inversion.
    Mat::at<Vec3b>(i,j) = Vec3b(255,255,255) - Mat::at<Vec3b>(i,j);

    need to access 2d array - just one row
    const double* Mi = M.ptr<double>(i);
    for(int j=0;j<M.cols;j++) sum += std::max(Mi[j],0.);

    [3] accessing data
        (1) at() method
        (2) raw C array access
            e.g)
                Mat M(3,3,CV_32F);
                float *fptr = (float *)M.data;
                int i_step = M.step[0]/M.elemsize();    (step[0] - row)
                int j_step = M.step[1]/M.elemsize();    (step[1] - column)
                fptr[1*i_step + 2*j_step] = 10;

    [4] 'const' rule
        use 'const' to all the 'input' parameter!


    [5] mixChannels

        mixChannels(const Mat *src, int nsrc, Mat* dst, int ndst, const int *fromTo, size_t npairs)

        src - input array or vector of matrices.
        nsrc - number of matrices in src.

        dst - output array or vector of matrices.
        ndst - number of matrices in dst.

        fromTo - Array of index pairs specifying which channels are copied and where.
        npairs - number of index pairs in fromTo
        e.g)
        int from_to[] = { 0,2, 1,1, 2,0, 3,0 };
        mixChannels( &rgba, 1, out, 2, from_to, 4 );
*/